package com.lp.easymethodlink.service;

import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.util.Query;
import com.lp.easymethodlink.model.CallHierarchyNode;
import com.lp.easymethodlink.util.PsiAnnotationUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 调用链路分析服务
 */
public class CallHierarchyService {
    
    private Project project;
    
    public CallHierarchyService(Project project) {
        this.project = project;
    }
    
    /**
     * 构庺方法的调用链路
     * @param method 目标方法
     * @return 调用链路根节点
     */
    public CallHierarchyNode buildCallHierarchy(PsiMethod method) {
        CallHierarchyNode rootNode = createNodeFromMethod(method);
        // 构建完整的调用链路
        buildCallHierarchyRecursive(rootNode, method, 3); // 限制3层深度以避免过深的递归
        return rootNode;
    }
    
    /**
     * 递归构庺调用链路
     * @param node 当前节点
     * @param method 当前方法
     * @param depth 剩余深度
     */
    private void buildCallHierarchyRecursive(CallHierarchyNode node, PsiMethod method, int depth) {
        if (depth <= 0) {
            return; // 达到最大深度限制
        }
        
        // 查找调用者
        List<PsiMethod> callers = findCallers(method);
        
        for (PsiMethod caller : callers) {
            CallHierarchyNode callerNode = createNodeFromMethod(caller);
            node.addChild(callerNode);
            // 递归构庺调用链路
            buildCallHierarchyRecursive(callerNode, caller, depth - 1);
        }
    }
    
    /**
     * 从方法创庺节点
     * @param method 方法
     * @return 节点
     */
    private CallHierarchyNode createNodeFromMethod(PsiMethod method) {
        PsiClass containingClass = method.getContainingClass();
        String className = containingClass != null ? containingClass.getName() : "Unknown";
        CallHierarchyNode node = new CallHierarchyNode(className, method.getName());
        
        // 尝试获取方法描述
        String description = PsiAnnotationUtils.getMethodDescription(method);
        node.setMethodDescription(description);
        
        // 检查是否为Controller方法
        checkControllerMethod(method, node);
        
        return node;
    }
    
    /**
     * 检查是否为Controller方法并提取相关信息
     * @param method 方法
     * @param node 节点
     */
    private void checkControllerMethod(PsiMethod method, CallHierarchyNode node) {
        PsiClass containingClass = method.getContainingClass();
        if (containingClass == null) return;
        
        // 检查类是否有@RestController或@Controller注解
        boolean isController = PsiAnnotationUtils.hasClassAnnotation(containingClass, "org.springframework.stereotype.Controller") ||
                              PsiAnnotationUtils.hasClassAnnotation(containingClass, "org.springframework.web.bind.annotation.RestController");
        
        if (isController) {
            // 获取API路径
            String classMapping = PsiAnnotationUtils.getClassAnnotationValue(containingClass, "org.springframework.web.bind.annotation.RequestMapping");
            String methodMapping = PsiAnnotationUtils.getMethodAnnotationValue(method, "org.springframework.web.bind.annotation.RequestMapping");
            
            // 如果没有@RequestMapping，检查其他HTTP方法注解
            String httpMethod = "REQUEST";
            if (methodMapping == null || methodMapping.isEmpty()) {
                String[] httpMethods = {"GetMapping", "PostMapping", "PutMapping", "DeleteMapping", "PatchMapping"};
                String[] httpMethodNames = {"GET", "POST", "PUT", "DELETE", "PATCH"};
                
                for (int i = 0; i < httpMethods.length; i++) {
                    methodMapping = PsiAnnotationUtils.getMethodAnnotationValue(method, 
                        "org.springframework.web.bind.annotation." + httpMethods[i]);
                    if (methodMapping != null && !methodMapping.isEmpty()) {
                        httpMethod = httpMethodNames[i];
                        break;
                    }
                }
            }
            
            // 构造完整路径
            String fullPath = "";
            if (classMapping != null && !classMapping.isEmpty()) {
                fullPath += classMapping;
            }
            if (methodMapping != null && !methodMapping.isEmpty()) {
                if (!methodMapping.startsWith("/") && !fullPath.endsWith("/")) {
                    fullPath += "/";
                }
                fullPath += methodMapping;
            }
            
            if (!fullPath.isEmpty()) {
                node.setApiPath(fullPath);
                node.setHttpMethod(httpMethod);
            }
        }
    }
    
    /**
     * 查找方法的所有调用者
     * @param method 方法
     * @return 调用者列表
     */
    public List<PsiMethod> findCallers(PsiMethod method) {
        List<PsiMethod> callers = new ArrayList<>();
        
        PsiClass containingClass = method.getContainingClass();
        String className = containingClass != null ? containingClass.getName() : "Unknown";
        String methodName = method.getName();
        
        System.out.println("=== Starting search for callers of: " + className + "." + methodName + " ===");
        System.out.println("Method signature: " + method.getText());
        System.out.println("Containing file: " + method.getContainingFile().getName());
        
        if (containingClass != null) {
            System.out.println("Class qualified name: " + containingClass.getQualifiedName());
            System.out.println("Is interface: " + containingClass.isInterface());
        }

        try {
            // 使用项目范围搜索，然后扩展到所有范围
            GlobalSearchScope[] scopes = {
                GlobalSearchScope.projectScope(project),
                GlobalSearchScope.allScope(project)
            };
            
            for (int i = 0; i < scopes.length; i++) {
                GlobalSearchScope searchScope = scopes[i];
                String scopeName = (i == 0) ? "project scope" : "all scope";
                System.out.println("\n--- Searching in " + scopeName + " ---");
                
                // 使用MethodReferencesSearch查找方法的所有引用
                Query<PsiReference> query = MethodReferencesSearch.search(method, searchScope, true);
                
                query.forEach(reference -> {
                    PsiElement element = reference.getElement();
                    if (element != null) {
                        System.out.println("Found reference: " + element.getText());
                        System.out.println("  - File: " + element.getContainingFile().getName());
                        System.out.println("  - Element type: " + element.getClass().getSimpleName());
                        
                        // 找到包含引用的方法
                        PsiMethod callerMethod = findContainingMethod(element);
                        if (callerMethod != null) {
                            PsiClass callerClass = callerMethod.getContainingClass();
                            String callerClassName = callerClass != null ? callerClass.getName() : "Unknown";
                            System.out.println("  - Found in method: " + callerClassName + "." + callerMethod.getName());
                            
                            if (!callerMethod.equals(method)) {
                                boolean alreadyExists = callers.stream()
                                    .anyMatch(existing -> 
                                        existing.getName().equals(callerMethod.getName()) &&
                                        existing.getContainingClass() != null &&
                                        callerMethod.getContainingClass() != null &&
                                        existing.getContainingClass().getQualifiedName() != null &&
                                        existing.getContainingClass().getQualifiedName().equals(
                                            callerMethod.getContainingClass().getQualifiedName()
                                        )
                                    );
                                
                                if (!alreadyExists) {
                                    callers.add(callerMethod);
                                    System.out.println("  ✓ Added caller: " + callerClassName + "." + callerMethod.getName());
                                } else {
                                    System.out.println("  - Already exists: " + callerClassName + "." + callerMethod.getName());
                                }
                            } else {
                                System.out.println("  - Skipped self-reference");
                            }
                        } else {
                            System.out.println("  - No containing method found");
                        }
                    }
                });
                
                if (callers.size() > 0) {
                    System.out.println("Found " + callers.size() + " callers in " + scopeName + ", stopping search.");
                    break;
                }
            }
            
            // 如果是接口方法，也查找实现类的调用
            if (containingClass != null && containingClass.isInterface()) {
                System.out.println("\n--- Searching for interface method implementations ---");
                findCallersForInterfaceMethod(method, callers, GlobalSearchScope.allScope(project));
            }
            
            // 如果是实现类方法，也查找对应接口方法的调用
            if (containingClass != null && !containingClass.isInterface()) {
                System.out.println("\n--- Searching for interface method callers (implementation class) ---");
                findCallersForImplementationMethod(method, callers, GlobalSearchScope.allScope(project));
            }
            
            // 如果还是没找到，尝试文本搜索作为后备方案
            if (callers.isEmpty()) {
                System.out.println("\n--- Performing text-based search as fallback ---");
                findCallersUsingTextSearch(method, callers);
            }
            
            System.out.println("\n=== Search completed. Total callers found: " + callers.size() + " ===");
            
        } catch (Exception e) {
            System.err.println("Error finding callers: " + e.getMessage());
            e.printStackTrace();
        }

        return callers;
    }
    
    /**
     * 为接口方法查找调用者
     * @param interfaceMethod 接口方法
     * @param callers 调用者列表
     * @param searchScope 搜索范围
     */
    private void findCallersForInterfaceMethod(PsiMethod interfaceMethod, List<PsiMethod> callers, GlobalSearchScope searchScope) {
        PsiClass interfaceClass = interfaceMethod.getContainingClass();
        if (interfaceClass == null) return;
        
        System.out.println("Finding callers for interface method: " + interfaceClass.getName() + "." + interfaceMethod.getName());
        
        // 使用ClassInheritorsSearch查找接口的所有实现类
        try {
            // 简化处理：直接搜索方法名相同的方法调用
            // 这种方法虽然不够精确，但能找到大部分调用
            String methodName = interfaceMethod.getName();
            
            // 在整个项目中搜索方法名
            PsiManager psiManager = PsiManager.getInstance(project);
            // 这里我们简化处理，直接返回，因为主要的搜索逻辑已经在主方法中
            System.out.println("Interface method search completed for: " + methodName);
        } catch (Exception e) {
            System.err.println("Error in findCallersForInterfaceMethod: " + e.getMessage());
        }
    }
    
    /**
     * 检查方法是否重写了另一个方法
     * @param method 方法
     * @param superMethod 父方法
     * @return 是否重写
     */
    private boolean isMethodOverride(PsiMethod method, PsiMethod superMethod) {
        // 简单检查方法名和参数数量
        if (!method.getName().equals(superMethod.getName())) {
            return false;
        }
        
        PsiParameter[] params1 = method.getParameterList().getParameters();
        PsiParameter[] params2 = superMethod.getParameterList().getParameters();
        
        return params1.length == params2.length;
    }

    /**
     * 查找包含指定元素的方法
     * @param element PSI元素
     * @return 包含该元素的方法
     */
    private PsiMethod findContainingMethod(PsiElement element) {
        while (element != null) {
            if (element instanceof PsiMethod) {
                return (PsiMethod) element;
            }
            element = element.getParent();
        }
        return null;
    }
    
    /**
     * 使用文本搜索查找方法调用者（后备方案）
     * @param method 目标方法
     * @param callers 调用者列表
     */
    private void findCallersUsingTextSearch(PsiMethod method, List<PsiMethod> callers) {
        try {
            String methodName = method.getName();
            PsiClass containingClass = method.getContainingClass();
            if (containingClass == null) return;
            
            String className = containingClass.getName();
            System.out.println("Searching for text patterns: " + className + "." + methodName + " or ." + methodName + "(");
            
            // 搜索模式：可能的调用方式
            String[] searchPatterns = {
                className.toLowerCase() + "." + methodName,  // 小写类名调用
                className + "." + methodName,                // 原始类名调用
                "." + methodName + "(",                     // 直接方法调用
                methodName + "("                           // 简单方法调用
            };
            
            for (String pattern : searchPatterns) {
                System.out.println("Searching for pattern: " + pattern);
                // 这里可以使用更高级的文本搜索API
                // 由于API限制，这里暂时作为占位符
            }
            
            System.out.println("Text search completed. No additional callers found through text search.");
            
        } catch (Exception e) {
            System.err.println("Error in text search: " + e.getMessage());
        }
    }
    
    /**
     * 为实现类方法查找对应接口方法的调用者
     * @param implMethod 实现类方法
     * @param callers 调用者列表
     * @param searchScope 搜索范围
     */
    private void findCallersForImplementationMethod(PsiMethod implMethod, List<PsiMethod> callers, GlobalSearchScope searchScope) {
        PsiClass implClass = implMethod.getContainingClass();
        if (implClass == null) return;
        
        System.out.println("Looking for interfaces implemented by: " + implClass.getName());
        
        try {
            // 获取实现类实现的所有接口
            PsiClass[] interfaces = implClass.getInterfaces();
            
            for (PsiClass interfaceClass : interfaces) {
                System.out.println("Found interface: " + interfaceClass.getName());
                
                // 在接口中查找同名方法
                PsiMethod[] interfaceMethods = interfaceClass.findMethodsByName(implMethod.getName(), false);
                
                for (PsiMethod interfaceMethod : interfaceMethods) {
                    if (isMethodSignatureMatch(interfaceMethod, implMethod)) {
                        System.out.println("Found matching interface method: " + interfaceClass.getName() + "." + interfaceMethod.getName());
                        
                        // 搜索接口方法的调用者
                        Query<PsiReference> query = MethodReferencesSearch.search(interfaceMethod, searchScope, true);
                        
                        query.forEach(reference -> {
                            PsiElement element = reference.getElement();
                            if (element != null) {
                                System.out.println("Found interface method reference: " + element.getText());
                                System.out.println("  - File: " + element.getContainingFile().getName());
                                
                                PsiMethod callerMethod = findContainingMethod(element);
                                if (callerMethod != null && !callerMethod.equals(interfaceMethod) && !callerMethod.equals(implMethod)) {
                                    PsiClass callerClass = callerMethod.getContainingClass();
                                    String callerClassName = callerClass != null ? callerClass.getName() : "Unknown";
                                    
                                    boolean alreadyExists = callers.stream()
                                        .anyMatch(existing -> 
                                            existing.getName().equals(callerMethod.getName()) &&
                                            existing.getContainingClass() != null &&
                                            callerMethod.getContainingClass() != null &&
                                            existing.getContainingClass().getQualifiedName() != null &&
                                            existing.getContainingClass().getQualifiedName().equals(
                                                callerMethod.getContainingClass().getQualifiedName()
                                            )
                                        );
                                    
                                    if (!alreadyExists) {
                                        callers.add(callerMethod);
                                        System.out.println("  ✓ Added interface caller: " + callerClassName + "." + callerMethod.getName());
                                    }
                                }
                            }
                        });
                    }
                }
            }
            
        } catch (Exception e) {
            System.err.println("Error in findCallersForImplementationMethod: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 检查两个方法的签名是否匹配
     * @param method1 方法1
     * @param method2 方法2
     * @return 是否匹配
     */
    private boolean isMethodSignatureMatch(PsiMethod method1, PsiMethod method2) {
        // 检查方法名
        if (!method1.getName().equals(method2.getName())) {
            return false;
        }
        
        // 检查参数数量
        PsiParameter[] params1 = method1.getParameterList().getParameters();
        PsiParameter[] params2 = method2.getParameterList().getParameters();
        
        if (params1.length != params2.length) {
            return false;
        }
        
        // 简单检查，实际应用中可能需要更详细的类型检查
        return true;
    }
}